home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************************
- * avra - Assembler for the Atmel AVR microcontroller series
- * Copyright (C) 1998-1999 Jon Anders Haugum
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- *
- * Author of avra can be reached at:
- * email: jonah@omegav.ntnu.no
- * www: http://www.omegav.ntnu.no/~jonah/el/avra.html
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
-
- #include "misc.h"
- #include "args.h"
- #include "avra.h"
- #include "device.h"
-
- enum
- {
- DIRECTIVE_BYTE = 0,
- DIRECTIVE_CSEG,
- DIRECTIVE_DB,
- DIRECTIVE_DEF,
- DIRECTIVE_DEVICE,
- DIRECTIVE_DSEG,
- DIRECTIVE_DW,
- DIRECTIVE_ENDM,
- DIRECTIVE_ENDMACRO,
- DIRECTIVE_EQU,
- DIRECTIVE_ESEG,
- DIRECTIVE_EXIT,
- DIRECTIVE_INCLUDE,
- DIRECTIVE_LIST,
- DIRECTIVE_LISTMAC,
- DIRECTIVE_MACRO,
- DIRECTIVE_NOLIST,
- DIRECTIVE_ORG,
- DIRECTIVE_SET,
- DIRECTIVE_DEFINE,
- DIRECTIVE_UNDEF,
- DIRECTIVE_IFDEF,
- DIRECTIVE_IFNDEF,
- DIRECTIVE_IF,
- DIRECTIVE_ELSE,
- DIRECTIVE_ELIF,
- DIRECTIVE_ENDIF,
- DIRECTIVE_MESSAGE,
- DIRECTIVE_WARNING,
- DIRECTIVE_ERROR,
- DIRECTIVE_COUNT
- };
-
- char *directive_list[] =
- {
- "BYTE",
- "CSEG",
- "DB",
- "DEF",
- "DEVICE",
- "DSEG",
- "DW",
- "ENDM",
- "ENDMACRO",
- "EQU",
- "ESEG",
- "EXIT",
- "INCLUDE",
- "LIST",
- "LISTMAC",
- "MACRO",
- "NOLIST",
- "ORG",
- "SET",
- "DEFINE",
- "UNDEF",
- "IFDEF",
- "IFNDEF",
- "IF",
- "ELSE",
- "ELIF",
- "ENDIF",
- "MESSAGE",
- "WARNING",
- "ERROR"
- };
-
-
- int parse_directive(struct prog_info *pi, int pass)
- {
- int directive, ok = True, i;
- char *next, *data;
- struct file_info *fi_bak;
- struct label *label;
- struct def *def;
-
- next = get_next_token(pi->fi->scratch, TERM_SPACE);
- for(i = 0; pi->fi->scratch[i] != '\0'; i++)
- pi->fi->scratch[i] = toupper(pi->fi->scratch[i]);
- directive = get_directive_type(pi->fi->scratch + 1);
- if(directive == -1)
- {
- print_msg(pi, MSGTYPE_ERROR, "Unknown directive: %s", pi->fi->scratch);
- return(True);
- }
- switch(directive)
- {
- case DIRECTIVE_BYTE:
- if(!next)
- {
- print_msg(pi, MSGTYPE_ERROR, ".BYTE needs an operand");
- return(True);
- }
- if(pi->segment != SEGMENT_DATA)
- print_msg(pi, MSGTYPE_ERROR, ".BYTE directive can only be used in data segment (.DSEG)");
- get_next_token(next, TERM_END);
- if(!get_expr(pi, next, &i))
- return(False);
- if((pass == PASS_2) && pi->list_line && pi->list_on)
- {
- fprintf(pi->list_file, "%06x %s", pi->dseg_addr, pi->list_line);
- pi->list_line = NULL;
- }
- pi->dseg_addr += i;
- if(pass == PASS_1)
- pi->dseg_count++;
- break;
- case DIRECTIVE_CSEG:
- pi->segment = SEGMENT_CODE;
- break;
- case DIRECTIVE_DB:
- return(parse_db(pi, next, pass));
- break;
- case DIRECTIVE_DEF:
- if(!next)
- {
- print_msg(pi, MSGTYPE_ERROR, ".DEF needs an operand");
- return(True);
- }
- data = get_next_token(next, TERM_EQUAL);
- if(!(data && (tolower(data[0]) == 'r') && isdigit(data[1])))
- {
- print_msg(pi, MSGTYPE_ERROR, "%s needs a register (e.g. .def BZZZT = r16)", next);
- return(True);
- }
- i = atoi(&data[1]);
- if(i > 31)
- print_msg(pi, MSGTYPE_ERROR, "R%d is not a valid register", i);
- for(def = pi->first_def; def; def = def->next)
- if(!nocase_strcmp(def->name, next))
- {
- def->reg = i;
- return(True);
- }
- def = malloc(sizeof(struct def));
- if(!def)
- {
- print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
- return(False);
- }
- def->next = NULL;
- if(pi->last_def)
- pi->last_def->next = def;
- else
- pi->first_def = def;
- pi->last_def = def;
- def->name = malloc(strlen(next) + 1);
- if(!def->name)
- {
- print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
- return(False);
- }
- strcpy(def->name, next);
- def->reg = i;
- break;
- case DIRECTIVE_DEVICE:
- if(pass == PASS_2)
- return(True);
- if(!next)
- {
- print_msg(pi, MSGTYPE_ERROR, ".DEVICE needs an operand");
- return(True);
- }
- get_next_token(next, TERM_END);
- pi->device = get_device(next);
- if(!pi->device)
- print_msg(pi, MSGTYPE_ERROR, "Unknown device: %s", next);
- break;
- case DIRECTIVE_DSEG:
- pi->segment = SEGMENT_DATA;
- break;
- case DIRECTIVE_DW:
- if(pi->segment == SEGMENT_DATA)
- {
- print_msg(pi, MSGTYPE_ERROR, "Can't use .DW directive in data segment (.DSEG)");
- return(True);
- }
- while(next)
- {
- data = get_next_token(next, TERM_COMMA);
- if(!get_expr(pi, next, &i))
- return(False);
- if((i < -32768) || (i > 65535))
- print_msg(pi, MSGTYPE_ERROR, "Value %d is out of range (-32768 <= k <= 65535)", i);
- if(pi->segment == SEGMENT_EEPROM)
- {
- if(pass == PASS_2)
- {
- write_ee_byte(pi, pi->eseg_addr, (unsigned char)i);
- write_ee_byte(pi, pi->eseg_addr + 1, (unsigned char)(i >> 8));
- }
- pi->eseg_addr += 2;
- if(pass == PASS_1)
- pi->eseg_count += 2;
- }
- else
- {
- if((pass == PASS_2) && pi->hfi)
- write_prog_word(pi, pi->cseg_addr, i);
- pi->cseg_addr++;
- if(pass == PASS_1)
- pi->cseg_count++;
- }
- next = data;
- }
- break;
- case DIRECTIVE_ENDM:
- case DIRECTIVE_ENDMACRO:
- print_msg(pi, MSGTYPE_ERROR, "No .MACRO found before .ENDMACRO");
- break;
- case DIRECTIVE_EQU:
- if(!next)
- {
- print_msg(pi, MSGTYPE_ERROR, ".EQU needs an operand");
- return(True);
- }
- data = get_next_token(next, TERM_EQUAL);
- if(!data)
- {
- print_msg(pi, MSGTYPE_ERROR, "%s needs an expression (e.g. .EQU BZZZT = 0x2a)", next);
- return(True);
- }
- get_next_token(data, TERM_END);
- if(!get_expr(pi, data, &i))
- return(False);
- for(label = pi->first_label; label; label = label->next)
- {
- if(!nocase_strcmp(label->name, next))
- {
- print_msg(pi, MSGTYPE_ERROR, "%s have already been defined as a label", next);
- return(True);
- }
- }
- for(label = pi->first_variable; label; label = label->next)
- if(!nocase_strcmp(label->name, next))
- {
- print_msg(pi, MSGTYPE_ERROR, "%s have already been defined as a .SET variable", next);
- return(True);
- }
- for(label = pi->first_constant; label; label = label->next)
- if(!nocase_strcmp(label->name, next))
- {
- print_msg(pi, MSGTYPE_ERROR, "Can't redefine constant %s, use .SET instead", next);
- return(True);
- }
- label = malloc(sizeof(struct label));
- if(!label)
- {
- print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
- return(False);
- }
- label->next = NULL;
- if(pi->last_constant)
- pi->last_constant->next = label;
- else
- pi->first_constant = label;
- pi->last_constant = label;
- label->name = malloc(strlen(next) + 1);
- if(!label->name)
- {
- print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
- return(False);
- }
- strcpy(label->name, next);
- label->value = i;
- break;
- case DIRECTIVE_ESEG:
- pi->segment = SEGMENT_EEPROM;
- break;
- case DIRECTIVE_EXIT:
- pi->fi->exit_file = True;
- break;
- case DIRECTIVE_INCLUDE:
- if(!next)
- {
- print_msg(pi, MSGTYPE_ERROR, "Nothing to include");
- return(True);
- }
- next = term_string(pi, next);
- if((pass == PASS_2) && pi->list_line && pi->list_on)
- {
- fprintf(pi->list_file, " %s", pi->list_line);
- pi->list_line = NULL;
- }
- fi_bak = pi->fi;
- ok = parse_file(pi, next, pass);
- pi->fi = fi_bak;
- break;
- case DIRECTIVE_LIST:
- if(pass == PASS_2)
- pi->list_on = True;
- break;
- case DIRECTIVE_LISTMAC:
- if(pass == PASS_2)
- SET_ARG(pi->args, ARG_LISTMAC, True);
- break;
- case DIRECTIVE_MACRO:
- return(read_macro(pi, next, pass));
- break;
- case DIRECTIVE_NOLIST:
- if(pass == PASS_2)
- pi->list_on = False;
- break;
- case DIRECTIVE_ORG:
- if(!next)
- {
- print_msg(pi, MSGTYPE_ERROR, ".ORG needs an operand");
- return(True);
- }
- get_next_token(next, TERM_END);
- if(!get_expr(pi, next, &i))
- return(False);
- switch(pi->segment)
- {
- case SEGMENT_CODE:
- pi->cseg_addr = i;
- break;
- case SEGMENT_DATA:
- pi->dseg_addr = i;
- break;
- case SEGMENT_EEPROM:
- pi->eseg_addr = i;
- }
- if(pi->fi->label)
- pi->fi->label->value = i;
- break;
- case DIRECTIVE_SET:
- if(!next)
- {
- print_msg(pi, MSGTYPE_ERROR, ".SET needs an operand");
- return(True);
- }
- data = get_next_token(next, TERM_EQUAL);
- if(!data)
- {
- print_msg(pi, MSGTYPE_ERROR, "%s needs an expression (e.g. .SET BZZZT = 0x2a)", next);
- return(True);
- }
- get_next_token(data, TERM_END);
- if(!get_expr(pi, data, &i))
- return(False);
- for(label = pi->first_label; label; label = label->next)
- if(!nocase_strcmp(label->name, next))
- {
- print_msg(pi, MSGTYPE_ERROR, "%s have already been defined as a label", next);
- return(True);
- }
- for(label = pi->first_constant; label; label = label->next)
- if(!nocase_strcmp(label->name, next))
- {
- print_msg(pi, MSGTYPE_ERROR, "%s have already been defined as a .EQU constant", next);
- return(True);
- }
- for(label = pi->first_variable; label; label = label->next)
- if(!nocase_strcmp(label->name, next))
- {
- label->value = i;
- return(True);
- }
- label = malloc(sizeof(struct label));
- if(!label)
- {
- print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
- return(False);
- }
- label->next = NULL;
- if(pi->last_variable)
- pi->last_variable->next = label;
- else
- pi->first_variable = label;
- pi->last_variable = label;
- label->name = malloc(strlen(next) + 1);
- if(!label->name)
- {
- print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
- return(False);
- }
- strcpy(label->name, next);
- label->value = i;
- break;
- case DIRECTIVE_DEFINE:
- if(!next)
- {
- print_msg(pi, MSGTYPE_ERROR, ".DEFINE needs an operand");
- return(True);
- }
- data = get_next_token(next, TERM_SPACE);
- if(data)
- {
- get_next_token(data, TERM_END);
- if(!get_expr(pi, data, &i))
- return(False);
- }
- else
- i = 1;
- for(label = pi->first_label; label; label = label->next)
- if(!nocase_strcmp(label->name, next))
- {
- print_msg(pi, MSGTYPE_ERROR, "%s have already been defined as a label", next);
- return(True);
- }
- for(label = pi->first_variable; label; label = label->next)
- if(!nocase_strcmp(label->name, next))
- {
- print_msg(pi, MSGTYPE_ERROR, "%s have already been defined as a .SET variable", next);
- return(True);
- }
- for(label = pi->first_constant; label; label = label->next)
- if(!nocase_strcmp(label->name, next))
- {
- print_msg(pi, MSGTYPE_ERROR, "Can't redefine constant %s, use .SET instead", next);
- return(True);
- }
- label = malloc(sizeof(struct label));
- if(!label)
- {
- print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
- return(False);
- }
- label->next = NULL;
- if(pi->last_constant)
- pi->last_constant->next = label;
- else
- pi->first_constant = label;
- pi->last_constant = label;
- label->name = malloc(strlen(next) + 1);
- if(!label->name)
- {
- print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
- return(False);
- }
- strcpy(label->name, next);
- label->value = i;
- break;
- case DIRECTIVE_UNDEF: // TODO
- break;
- case DIRECTIVE_IFDEF:
- if(!next)
- {
- print_msg(pi, MSGTYPE_ERROR, ".IFDEF needs an operand");
- return(True);
- }
- get_next_token(next, TERM_END);
- if(get_symbol(pi, next, NULL))
- pi->conditional_depth++;
- else
- {
- if(!spool_conditional(pi, False))
- return(False);
- }
- break;
- case DIRECTIVE_IFNDEF:
- if(!next)
- {
- print_msg(pi, MSGTYPE_ERROR, ".IFNDEF needs an operand");
- return(True);
- }
- get_next_token(next, TERM_END);
- if(get_symbol(pi, next, NULL))
- {
- if(!spool_conditional(pi, False))
- return(False);
- }
- else
- pi->conditional_depth++;
- break;
- case DIRECTIVE_IF:
- if(!next)
- {
- print_msg(pi, MSGTYPE_ERROR, ".IF needs an expression");
- return(True);
- }
- get_next_token(next, TERM_END);
- if(!get_expr(pi, next, &i))
- return(False);
- if(i)
- pi->conditional_depth++;
- else
- {
- if(!spool_conditional(pi, False))
- return(False);
- }
- break;
- case DIRECTIVE_ELSE:
- case DIRECTIVE_ELIF:
- if(!spool_conditional(pi, True))
- return(False);
- break;
- case DIRECTIVE_ENDIF:
- if(pi->conditional_depth == 0)
- print_msg(pi, MSGTYPE_ERROR, "Too many .ENDIF");
- else
- pi->conditional_depth--;
- break;
- case DIRECTIVE_MESSAGE:
- if(pass == PASS_1)
- return(True);
- if(!next)
- {
- print_msg(pi, MSGTYPE_ERROR, "No message string supplied");
- return(True);
- }
- next = term_string(pi, next);
- print_msg(pi, MSGTYPE_MESSAGE, next);
- break;
- case DIRECTIVE_WARNING:
- if(pass == PASS_1)
- return(True);
- if(!next)
- {
- print_msg(pi, MSGTYPE_ERROR, "No warning string supplied");
- return(True);
- }
- next = term_string(pi, next);
- print_msg(pi, MSGTYPE_WARNING, next);
- break;
- case DIRECTIVE_ERROR:
- if(pass == PASS_1)
- return(True);
- if(!next)
- {
- print_msg(pi, MSGTYPE_ERROR, "No error string supplied");
- return(True);
- }
- next = term_string(pi, next);
- print_msg(pi, MSGTYPE_ERROR, next);
- break;
- }
- return(ok);
- }
-
-
- int get_directive_type(char *directive)
- {
- int i;
-
- for(i = 0; i < DIRECTIVE_COUNT; i++)
- if(!strcmp(directive, directive_list[i])) return(i);
- return(-1);
- }
-
-
- char *term_string(struct prog_info *pi, char *string)
- {
- int i;
-
- if(string[0] != '\"')
- print_msg(pi, MSGTYPE_ERROR, "String must be enclosed in \"-signs");
- else
- string++;
- for(i = 0; (string[i] != '\"') && !((string[i] == 10) || (string[i] == 13) || (string[i] == '\0')); i++);
- if((string[i] == 10) || (string[i] == 13) || (string[i] == '\0'))
- print_msg(pi, MSGTYPE_ERROR, "String is missing a closing \"-sign");
- string[i] = '\0';
- return(string);
- }
-
-
- int parse_db(struct prog_info *pi, char *next, int pass)
- {
- int i, count;
- char *data, prev;
-
- if(pi->segment == SEGMENT_DATA)
- {
- print_msg(pi, MSGTYPE_ERROR, "Can't use .DB directive in data segment (.DSEG)");
- return(True);
- }
- count = 0;
- while(next)
- {
- data = get_next_token(next, TERM_COMMA);
- if(next[0] == '\"')
- {
- next = term_string(pi, next);
- while(*next != '\0')
- {
- count++;
- write_db(pi, *next, &prev, count, pass);
- next++;
- }
- }
- else
- {
- if(!get_expr(pi, next, &i))
- return(False);
- if((i < -128) || (i > 255))
- print_msg(pi, MSGTYPE_ERROR, "Value %d is out of range (-128 <= k <= 255)", i);
- count++;
- write_db(pi, (char)i, &prev, count, pass);
- }
- next = data;
- }
- if(pi->segment == SEGMENT_CODE)
- {
- if((count % 2) == 1)
- {
- if(pass == PASS_2)
- write_prog_word(pi, pi->cseg_addr, prev & 0xff);
- pi->cseg_addr++;
- if(pass == PASS_1)
- pi->cseg_count++;
- }
- }
- return(True);
- }
-
-
- void write_db(struct prog_info *pi, char byte, char *prev, int count, int pass)
- {
- if(pi->segment == SEGMENT_EEPROM)
- {
- if(pass == PASS_2)
- write_ee_byte(pi, pi->eseg_addr, byte);
- pi->eseg_addr++;
- if(pass == PASS_1)
- pi->eseg_count++;
- }
- else /* pi->segment == SEGMENT_CODE */
- {
- if((count % 2) == 0)
- {
- if(pass == PASS_2)
- write_prog_word(pi, pi->cseg_addr, (byte << 8) | (*prev & 0xff));
- pi->cseg_addr++;
- if(pass == PASS_1)
- pi->cseg_count++;
- }
- else
- *prev = byte;
- }
- }
-
-
- int spool_conditional(struct prog_info *pi, int only_endif)
- {
- int current_depth = 0, do_next;
-
- if(pi->macro_line)
- {
- while((pi->macro_line = pi->macro_line->next))
- {
- pi->macro_call->line_index++;
- if(check_conditional(pi, pi->macro_line->line, ¤t_depth, &do_next, only_endif))
- {
- if(!do_next)
- return(True);
- }
- else
- return(False);
- }
- print_msg(pi, MSGTYPE_ERROR, "Found no closing .ENDIF in macro");
- }
- else
- {
- while(fgets(pi->fi->buff, LINEBUFFER_LENGTH, pi->fi->fp))
- {
- pi->fi->line_number++;
- if(check_conditional(pi, pi->fi->buff, ¤t_depth, &do_next, only_endif))
- {
- if(!do_next)
- return(True);
- }
- else
- return(False);
- }
- if(feof(pi->fi->fp))
- {
- print_msg(pi, MSGTYPE_ERROR, "Found no closing .ENDIF");
- return(True);
- }
- else
- {
- perror(pi->fi->include_file->name);
- return(False);
- }
- }
- return(True);
- }
-
-
- int check_conditional(struct prog_info *pi, char *buff, int *current_depth, int *do_next, int only_endif)
- {
- int i = 0;
- char *next;
-
- *do_next = False;
- while(IS_HOR_SPACE(buff[i]) && !IS_END(buff[i])) i++;
- if(buff[i] == '.')
- {
- i++;
- if(!nocase_strncmp(&buff[i], "if", 2))
- (*current_depth)++;
- else if(!nocase_strncmp(&buff[i], "endif", 5))
- {
- if(*current_depth == 0)
- return(True);
- (*current_depth)--;
- }
- else if(!only_endif && (*current_depth == 0))
- {
- if(!nocase_strncmp(&buff[i], "else", 4))
- {
- pi->conditional_depth++;
- return(True);
- }
- else if(!nocase_strncmp(&buff[i], "elif", 4))
- {
- next = get_next_token(&buff[i], TERM_SPACE);
- if(!next)
- {
- print_msg(pi, MSGTYPE_ERROR, ".ELIF needs an operand");
- return(True);
- }
- get_next_token(next, TERM_END);
- if(!get_expr(pi, next, &i))
- return(False);
- if(i)
- pi->conditional_depth++;
- else
- {
- if(!spool_conditional(pi, False))
- return(False);
- }
- return(True);
- }
- }
- }
- *do_next = True;
- return(True);
- }
-